package com.atyun.rejectPolicy;

import com.atyun.gaojin.notify.AlterNotify;
import com.atyun.gaojin.notify.deduplicator.AlterDeduplicator;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 拒绝策略RejectedExecutionHandler代理类
 * @Author: 云水瑶
 * @Date: 2025/5/1
*/
@Slf4j
public class RejectPolicyProxy {

    //通过createProxy创建RejectedExecutionHandler的代理对象
    public static RejectedExecutionHandler createProxy(RejectedExecutionHandler handler,
                                                       String poolName, AlterNotify notify, AlterDeduplicator alterDeduplicator) {
        return (RejectedExecutionHandler) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                new Class[]{RejectedExecutionHandler.class},
                new RejectedProxyInvocationHandler(handler, poolName, notify, alterDeduplicator));
    }

    public static class RejectedProxyInvocationHandler implements InvocationHandler {

        private RejectedExecutionHandler handler;
        private String poolName;
        private AlterNotify notify;
        private AlterDeduplicator alterDeduplicator;

        public RejectedProxyInvocationHandler(RejectedExecutionHandler handler, String poolName, AlterNotify notify, AlterDeduplicator alterDeduplicator) {
            this.handler = handler;
            this.poolName = poolName;
            this.notify = notify;
            this.alterDeduplicator = alterDeduplicator;
        }

        /**
         * invoke执行方法时需要触发告警
         * @Author: 云水瑶
         * @Date: 2025/5/1
        */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if(method.getName().equals("rejectedExecution")) {
                //触发告警
                Runnable command = (Runnable) args[0]; //根据rejectedExecution方法的参数列表来确定
                ThreadPoolExecutor executor = (ThreadPoolExecutor) args[1];
                String content = notify.shouldAlterNotify(poolName, command, executor);

                //触发告警之前，需要判断是否需要去重
                String alterKey = alterDeduplicator.getAlterKey(poolName, content);
                if(alterDeduplicator.shouldAlterDeduplication(alterKey, content, poolName)) {
                    //可以发送告警
                    notify.sendAlterNotify(poolName, command, executor);
                } else {
                    //不需要发送告警
                    log.debug("Alter was Deduplication: {}", content);
                }
            }
            return method.invoke(handler, args);
        }
    }

}
